package com.ytrsoft.im;

import cn.hutool.json.JSONUtil;
import com.ytrsoft.entity.Message;
import com.ytrsoft.entity.User;
import com.ytrsoft.enums.IMType;
import com.ytrsoft.service.UserService;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

public abstract class AbstractIM {

    protected final IMType type;

    private final UserService userService;
    private final Map<String, IMPresenter> presenters = new ConcurrentHashMap<>();

    private static final Logger log = LoggerFactory.getLogger(AbstractIM.class);

    public AbstractIM(UserService userService, IMType type) {
        this.userService = userService;
        this.type = type;
    }

    protected abstract void handleMessage(IMPresenter presenter);


    private void sendMessage(Session session, Object message, boolean isBinary) {
        try {
            if (isBinary) {
                ByteBuffer wrapped = ByteBuffer.wrap((byte[]) message);
                session.getBasicRemote().sendBinary(wrapped);
            } else {
                session.getBasicRemote().sendText((String) message);
            }
        } catch (IOException e) {
            log.error("发送消息失败: {}", e.getMessage());
        }
    }

    protected void sendText(IMPresenter presenter, String text) {
        sendMessage(presenter.getSession(), text, false);
    }

    protected void sendBinary(IMPresenter presenter, byte[] bytes) {
        sendMessage(presenter.getSession(), bytes, true);
    }

    protected void sendError(IMPresenter presenter, String error) {
        IMMessage<String> msg = new IMMessage<>();
        msg.setPayload(error);
        sendText(presenter, JSONUtil.toJsonStr(msg));
    }

    protected IMPresenter getToPresenter(IMPresenter presenter) {
        User toUser = presenter.getTo();
        return presenters.get(toUser.getId());
    }

    private int checkUser(IMPresenter presenter) {
        return (presenter.getFrom() == null) ? 1 : (presenter.getTo() == null ? 2 : -1);
    }

    private IMPresenter createPresenter(String fromUserId, String toUserId) {
        IMPresenter presenter = new IMPresenter();
        User fromUser = userService.findById(fromUserId);
        User toUser = userService.findById(toUserId);
        presenter.setFrom(fromUser);
        presenter.setTo(toUser);
        return presenter;
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("from") String from, @PathParam("to") String to) {
        IMPresenter presenter = createPresenter(from, to);
        presenter.setSession(session);
        presenter.setId(from);
        int state = checkUser(presenter);
        if (state == -1) {
            presenters.put(from, presenter);
        } else {
            String error = state == 1 ? "查找发送方失败" : "查找接收方失败";
            sendError(presenter, error);
        }
    }

    @OnMessage
    public void onMessage(Object payload, @PathParam("id") String id) {
        UUID reqId = UUID.fromString(id);
        IMPresenter presenter = presenters.get(reqId);
        if (type == IMType.TEXT) {
            Message message = JSONUtil.toBean((String) payload, Message.class);
            if (presenter != null) {
                presenter.setMessage(message);
            }
        } else {
            byte[] stream = (byte[]) payload;
            presenter.setStream(stream);
        }
        handleMessage(presenter);
    }

    @OnClose
    public void onClose(@PathParam("id") String id) {
        UUID reqId = UUID.fromString(id);
        presenters.remove(reqId);
        log.info("连接已关闭，id: {}", id);
    }

    @OnError
    public void onError(Throwable t, @PathParam("id") String id) {
        UUID reqId = UUID.fromString(id);
        presenters.remove(reqId);
        log.error("发生错误，id: {}, 错误信息: {}", id, t.getMessage());
    }
}
